
#define _XOPEN_SOURCE 500

#include <fcntl.h>
#include <math.h>
#include <malloc.h>
#include <string.h>

#include <stdio.h>
#include <stdlib.h>

#include <sys/stat.h>
#include <sys/types.h>

#include <unistd.h>

#include <errno.h>

#include "rsrcmanager.h"

#include "../utils.h"
#include "../log/log.h"

char* get_resource_filename_from_key( filekey_t fkey)
{

  char* filename = NULL;

  int L = strlen(RSRCMAN_DIRECTORY_PARTS)
            + 1
            + sizeof(filekey_t)
            + strlen(RSRCMAN_PART_EXT) + 1;

  if( !( filename = malloc(L*sizeof(char))) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                __func__,__LINE__);
    return NULL;
  }

  memset(filename,0,L*sizeof(char));

  strcpy(filename,RSRCMAN_DIRECTORY_PARTS);
  strncat(filename,"/",1);
  strncat(filename,fkey,sizeof(filekey_t));
  strcat(filename,RSRCMAN_PART_EXT);

  return filename;
}


localResource_s* RM_create_local_resource(char* name,
                                           filekey_t key,
                                           size_t size)
{
  localResource_s* lr = NULL;
  blockRange_s* blockRange;

  int fd;

  char* filename = get_resource_filename_from_key( key );

  if(!filename) return NULL;
  
  // Open the file for writing, 0 size it
  //(even if it already exist)
  if((fd = open( filename,
        O_WRONLY|O_TRUNC|O_CREAT, DEFAULT_PERM)) == -1)
  {
    LOG_add(LOG_ERROR, RSRCMAN"Unable to open %s: %s.",
                filename, strerror(errno));
    return NULL;
  }
  
  // Truncate the file to size
  if( ftruncate(fd,size) == -1 )
  {
    LOG_add(LOG_ERROR, RSRCMAN"Unable to truncate %s: %s.",
                  filename,strerror(errno));
    return NULL;
  }
  
  // Enougth for now
  if( close(fd) == -1 )
  {
    LOG_add(LOG_ERROR, RSRCMAN"Can't close %s: %s.",
             filename,strerror(errno));
    return NULL;
  }


  // Allocate the structure
  if( !(lr = malloc( sizeof(localResource_s))) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                __func__,__LINE__);
    return NULL;
  }

  memset(lr,0,sizeof(localResource_s));

  // No need to copy or allocate because
  // get_resource_filename_from_key already allocate memory
  lr->filename = filename;

  // Resource key
  memcpy(lr->key,key,sizeof(filekey_t));

  // Set the block size
  lr->block_size = DEFAULT_BLOCK_SIZE;

  // Calculate the size in blocks (upper)
  lr->size =
    (size_t)ceil((double)size/(double)(lr->block_size));

  // Calculate the last block real length
  lr->last_block_size = (size_t)(size - (lr->size)*(lr->block_size));

  // Create a void chained list
  lr->status = CL_create();
  
  // Create a block covering all the file
  // with status NONE
  if( !(blockRange = malloc(sizeof(blockRange_s))) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                __func__,__LINE__);
    return NULL;               
  }

  memset(blockRange,0,sizeof(blockRange_s));

  blockRange->bstatus = BSTAT_NONE;
  blockRange->pid = 0;
  blockRange->begin = 0;
  blockRange->end = lr->size - 1;

  CL_push(lr->status, blockRange);

  LOG_add(LOG_NOTICE,
              RSRCMAN"new resource allocated: %.32s:%s.",
              lr->key,lr->filename);

  return lr;
}

void RM_destroy_local_resource( localResource_s* lr )
{
  if(!lr) return;

  // Clean the chained list
  CL_map(lr->status,free);

  // Destroy it
  CL_destroy( lr->status );

  LOG_add(LOG_NOTICE,
              RSRCMAN"local resource %.32s:%s destroyed.",
              lr->key,lr->filename);

  // Clean the localResource structure
  free( lr->filename );

  // Clean the structure
  free( lr );
}

char RM_settle_down( void )
{
  char rv=0;

  rv |= RM_check_dir(RSRCMAN_DIRECTORY_PARTS,RSRCMAN_PERM_PARTS);
  rv |= RM_check_dir(RSRCMAN_DIRECTORY_SAVES,RSRCMAN_PERM_SAVES);
  rv |= RM_check_dir(RSRCMAN_DIRECTORY_INCOMING,RSRCMAN_PERM_INCOMING);

  return rv;
}

char RM_check_dir( char* path, int perms )
{
  struct stat buf;

  if( stat(path,&buf))
  {
    if( errno == ENOENT )
    {
      // Nothing live here...
      
      umask(0022);

      //...just create one
      if(mkdir(path,perms))
      {
        LOG_add(LOG_ERROR, RSRCMAN"can't create dir %s: %s",
                            path,
                            strerror(errno));
        return -1;
      }
 
      LOG_add(LOG_NOTICE, RSRCMAN"directory %s created.",
                            path);

      //Update buf
      if(stat(path,&buf))
      {
        LOG_add(LOG_ERROR, RSRCMAN"can't stat %s: %s",
                          path,
                          strerror(errno));
        return -1;
      }

    }
    else
    {
      LOG_add(LOG_ERROR, RSRCMAN"can't stat %s: %s",
                          path,
                          strerror(errno));
      return -1;
    }
  }
  
  // Some idiot put a file with same name in OUR WAY!
  if( !S_ISDIR(buf.st_mode))
  {
    LOG_add(LOG_ERROR, RSRCMAN"can't create dir %s: a file with same name already exist !",
                        path);
    return -1;
  }

  if( ((buf.st_mode) & (S_IRWXO|S_IRWXG|S_IRWXU)) != perms )
  {
    if( chmod(path,perms) )
    {
      LOG_add(LOG_ERROR, RSRCMAN"can't chmod %s to %o: %s",
                          path,
                          perms,
                          strerror(errno));
      return -1;                        
    }
  }

  return 0;
}

blockRange_s* RM_set_range_state(localResource_s* lr,
                        blockstatus_t status,
                        pid_t pid,
                        off_t first,
                        off_t last)
{
  return _RM_set_range_state(lr->status,
                          lr->size,
                          status,pid,first,last);
}

blockRange_s* _RM_set_range_state(CLNode_s* root,
                        size_t size,
                        blockstatus_t status,
                        pid_t pid,
                        off_t first,
                        off_t last)
{
  CLNode_s* node;
  blockRange_s* br;
  blockRange_s* br_tmp;

  off_t offset;

  if( first > last ) 
  {
    LOG_add(LOG_ERROR, RSRCMAN"_RM_set_range_state got an unvalid bloc: [%ld,%ld] size=%ld.\n",
                         first,last,size);
    return NULL;               
  }

  CLNode_s* remove_list = CL_create();

  // First step :
  // finding every enclosed bloc, delete it,
  // if the range overlap a bloc, concatenate it.
  for( node = CL_first(root); node; node=node->next )
  {
    br = (blockRange_s*)node->data;

    if(!br) continue;

    //    |-------------|
    // [?][?][AAAAAAAA][?][?]
    if( CONTAINS(first, br->begin, br->end, last)) 
    {
      free(br);
      
      node->data = NULL;

      CL_push(remove_list, node);
    }
    else
    {
      //      |---???
      // [AAAAAAAAAA]
      if( ENCLOSE( br->begin, first, br->end ) )
      {
        //    |-------|
        // [AAAAAAAAAAAA]
        if( ENCLOSE( br->begin, last, br->end) )
        {

          // |---------| 
          // [AAAAAAAAAAAA]
          if( br->begin == first )
          {
            br->begin = last + 1;
            
            // |-----------|
            //              [AA]
          }
          else
          {
            //   |-----|
            // [AAAAAAA]
            if( br->end == last )
            {
              br->end = first - 1;

              //    |----|
              // [A]      
            }
            else
            {

              offset = br->end;
            
              br->end = first - 1;

              //   |-------|
              //[A] 
            
              if( last != (size - 1) )
              {

                if( !(br_tmp = malloc( sizeof(blockRange_s))) )
                {
                  LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                           __func__,__LINE__);
                  return NULL;               
                }

               memset(br_tmp, 0, sizeof(blockRange_s));

                br_tmp->bstatus = br->bstatus;
                br_tmp->pid = br->pid;
                br_tmp->begin = last + 1;
                br_tmp->end = offset;

                CL_push(root, br_tmp);
              }
              //   |-------|
              //[A]         [A]
            }
          }
        }
        else
        //   |-------------|
        // [AAAAAAAA][?][BBBBB]
        {
          if( br->begin == first )
          {
            free(br);
            CL_push(remove_list, node);
          }
          else
            br->end = first - 1;

          //   |-----------|
          //[A]      [?][BBBBB]
        }

      }//if( ENCLOSE( br->begin, first, br->end ) )
      else
        // ???---|
        // AAAAAAAAA]
        if( ENCLOSE( br->begin, last, br->end) )
        {
          //NOTE:
          //   |------|
          //[AAAAAAAAAAAA]
          //Is not possible because it match 
          //previous cases.


          if( br->end == last )
          {
            //    |-------|
            // [BBB][?]    
            free(br);
        
            node->data = NULL;

            CL_push(remove_list, node);         
          }
          else
            br->begin = last + 1;

          // |---------|
          //[BBBB][?]   [AA]

        }//if( ENCLOSE( br->begin, last, br->end) )

    }//else( CONTAINS(first, br->begin, br->end, last)) 

  }//for( lc = CL_first(lr->status); lc; lc=lc->next )
  

  if( !(br_tmp = malloc( sizeof(blockRange_s))) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                __func__,__LINE__);
    return NULL;               
  }

  memset(br_tmp, 0, sizeof(blockRange_s));

  br_tmp->bstatus = status;
  br_tmp->pid = pid;
  br_tmp->begin = first;
  br_tmp->end = last;

  CL_push(root, br_tmp);

  // Remove the blocs from the chained list.
  for(node=CL_first(remove_list);node;node=node->next)
    CL_remove((CLNode_s*)(node->data));
  
  CL_destroy(remove_list);

  return br_tmp;
}

void _RM_stick_adjacent(CLNode_s* root)
{
  CLNode_s* node = NULL;
  CLNode_s* node2 = NULL;

  if( !(root) ) return;
  if( !(CL_first(root)) ) return;
  if( !(CL_first(root)->next) ) return;

  for(node=CL_first(root); node; node=node->next)
  {
    blockRange_s* br = (blockRange_s*)node->data;

    if(!br) continue;
    
    for(node2=CL_first(root); node2; node2=node2->next)
    {
      if( node2 == node ) continue;
      
      blockRange_s* br2 = (blockRange_s*)node2->data;
      
      if(!br2) continue;
      
      // [AAAAA][BBBBBB]
      if( (br->end +1 == br2->begin)
        &&(br->bstatus == br2->bstatus)
        &&(br->pid == br->pid) )
      {
        br->end = br2->end;

        free(br2);
        CL_remove(node2);

        break;
      }

    }//for( node2 )
    
  }//for( node )
  
  return;
}

void RM_stick_adjacent(localResource_s* lr)
{

  if(!lr) return;
  
  return _RM_stick_adjacent(lr->status);
}


size_t RM_return_matching_range(localResource_s* lr,
 char (*fmatching)(int state, blockRange_s* br, pid_t pid),
                            int max_state,
                            blockRange_s* rbr,
                            off_t first,
                            off_t last,
                            pid_t pid)
{

  CLNode_s* node;

  blockRange_s* lbr = NULL;
  off_t lbegin = 0;
  off_t lend = 0;

  if(!lr) return 0;
  if(!rbr) return 0;

  if( (first > last)||(last > lr->size) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"%s got an unvalid bloc: [%ld,%ld].\n",
                         __func__,
                         first,last);
    return 0;               
  }


  RM_stick_adjacent(lr);

  // State : 
  // 0- Search POSTPONED / matching pid.
  // 1- Search NONE.
  // 2- Search POSTPONED / whatever pid.

  int state;
  for(state=0;state<(max_state -1);state++)
  {
    
    for(node=CL_first(lr->status);node;node=node->next)
    {
      blockRange_s* br = (blockRange_s*)node->data;

      if(!br) continue;

      // The block range doesn't match the current
      //search state. (Take a look to the .h comments
      //for more informations)
      if( !fmatching(state,br,pid))
        continue;

      if( CONTAINS(first, br->begin, br->end, last) )
      { //    |----------------|
        // [?????][AAAAAAAAA][?????]
        
        if( (br->end - br->begin) > (lend - lbegin) ) 
        {
          lbr = br;
          lbegin = br->begin;
          lend = br->end;
        }

      }
      else
        if( CONTAINS(br->begin, first, last, br->end) )
        { //       |------|
          // [?][AAAAAAAAAAAA][?]

          if( (br->end - br->begin) > (lend - lbegin) ) 
          {
            lbr = br;
            lbegin = first;
            lend = last;
          }

        }
        else
          if( ENCLOSE(br->begin, first, br->end) )
          { //      |--------------|
            //  [AAAAAAAAAAA][?????????]

            if( (br->end - first) > (lend - lbegin) ) 
            {
              lbr = br;
              lbegin = first;
              lend = br->end;
            }

          }
          else
            if( ENCLOSE(br->begin,last,br->end))
            { //    |------------|
              // [??????][AAAAAAAAA]

              if( (last - br->begin) > (lend - lbegin) ) 
              {
                lbr = br;
                lbegin = br->begin;
                lend = last;
              }

            }

      }//for(node=CL_first(lr->status);node;node=node->next)

    // lbr != 0 means that a block was found.
    if(lbr)
      break;

  }//for(state=0;state<3;state++)

  rbr->begin = lbegin;
  rbr->end = lend;
  
  return (lend - lbegin);
}

blockRange_s* RM_reserve_block_range(localResource_s* lr,
                             off_t first,
                             off_t last,
                             pid_t pid)
{
  if(!lr) return NULL;

  blockRange_s br;

  size_t size;

  size = RM_return_matching_range(lr,
                                   fmatching_postponed, 1,
                                   &br, first, last, pid);
 
  if(!size)
    return NULL;

  // Now allocate the range for writing
  return RM_set_range_state( lr, BSTAT_POSTPONED, pid,
                             br.begin, br.end);
}

blockRange_s* RM_lock_write_block_range(localResource_s* lr,
                                        off_t first,
                                        off_t last,
                                        size_t msize,
                                        pid_t pid)
{
  if(!lr) return NULL;

  blockRange_s br;

  size_t size;

  // Find a lovely area to put our data
  size = RM_return_matching_range(lr,
                                   fmatching_writing, 2,
                                   &br, first, last, pid);
  
  if(!size) 
    return NULL;

  // Previously in 24^W the documentation:
  // return_matching_range doesn't allocate anything
  // so we have use the data to allocate a range.
  // (br is here only a 'nut' for begin and end)
  
  // The area is too big
  if( size > msize )
    br.end = br.begin + msize;

  // Now allocate the range for writing
  return RM_set_range_state( lr, BSTAT_WRITING, pid,
                             br.begin, br.end);

}

char RM_local_resource_to_disk(localResource_s* lr)
{
  FILE* fout = NULL;

  char* filename = NULL;

  CLNode_s* node;

  unsigned int l = strlen(RSRCMAN_DIRECTORY_SAVES)
                    + strlen(lr->key)
                    + strlen(RSRCMAN_SAVE_EXT) + 1;
  
  if( !(filename = malloc( l*sizeof(char) )) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                __func__,__LINE__);
    return -1;
  }

  strcpy(filename, RSRCMAN_DIRECTORY_SAVES);
  strncat(filename, lr->key, sizeof(filekey_t));
  strcat(filename, RSRCMAN_SAVE_EXT);

  if( !(fout = fopen(filename, "w")) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"Unable to open %s.",filename);
    return -1;
  }
 
  fprintf(fout,"%.32s\n",(char*)(&lr->key));
  fprintf(fout,"%s\n",lr->filename);
  fprintf(fout,"%u\n",lr->size);
  fprintf(fout,"%u\n",lr->block_size);
  fprintf(fout,"%u\n",lr->last_block_size);

  for( node = CL_first(lr->status); node; node=node->next )
  {
    blockRange_s* br = node->data;

    if(!br) continue;

#ifdef SOLARIS
    fprintf(fout, ";%ld;%ld;%d;%ld;\n",
#else
    fprintf(fout, ";%ld;%ld;%d;%d;\n",
#endif
              br->begin,
              br->end,
              br->bstatus,
              br->pid);
  }

  fclose(fout);

  free(filename);

  LOG_add(LOG_NOTICE, RSRCMAN"%.32s:%s saved to disk.",
            lr->key,lr->filename);

  return 0;
}

char RM_local_resource_from_disk(localResource_s* lr,
                                  char* name)
{
  if(!lr) return -1;
  
  // Clean the chained list
  CL_map(lr->status,free);

  CL_destroy( lr->status );

  // Create it
  lr->status = CL_create();

  FILE* fin = NULL;

  char* filename = NULL;

  unsigned int l = strlen(RSRCMAN_DIRECTORY_SAVES)
                    + strlen(lr->key)
                    + strlen(RSRCMAN_SAVE_EXT) + 1;
  
  if( !(filename = malloc( l*sizeof(char) )) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                __func__,__LINE__);
    return -1;
  }

  strcpy(filename, RSRCMAN_DIRECTORY_SAVES);
  strncat(filename, lr->key, sizeof(filekey_t));
  strcat(filename, RSRCMAN_SAVE_EXT);

  fprintf(stderr,"###%s\n",filename);

  if( !(fin = fopen(filename, "r")) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"Unable to open %s.",filename);
    return -1;
  } 

  fscanf(fin,"%32c\n", lr->key);
  fscanf(fin,"%as\n",(char**)(&(lr->filename)));
  fscanf(fin,"%u\n",&(lr->size));
  fscanf(fin,"%u\n",&(lr->block_size));
  fscanf(fin,"%u\n",&(lr->last_block_size));

  blockRange_s* br;

  while( !feof(fin) )
  {

    if( !(br = malloc( sizeof(blockRange_s))) )
    {
      LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                   __func__,__LINE__);
      return -1;
    }
    
    int rv;

#ifdef SOLARIS
    rv = fscanf(fin,";%ld;%ld;%d;%ld;\n",
#else
    rv = fscanf(fin,";%ld;%ld;%d;%d;\n",
#endif
                &(br->begin),
                &(br->end),
                (int*)&(br->bstatus),
                &(br->pid));

    fprintf(stderr,"##%d\n",rv);

    if( (rv == EOF)||(rv==0) )
      break;

    CL_push(lr->status, br);

  }
  
  
  LOG_add(LOG_NOTICE, RSRCMAN"%.32s:%s loaded from disk.",
            lr->key,lr->filename);

  return 0;
}

/***********************************************************/
/***********************************************************/
/***********************************************************/
/***********************************************************/

partialResource_s* RMC_create_partial_resource( filekey_t fkey,
                                      off_t start,
                                      off_t end,
                                      size_t block_size)
{
  partialResource_s* pr = NULL;

  if( !(pr = malloc( sizeof(partialResource_s))) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                __func__,__LINE__);
    return NULL;
  }
  
  memset(pr,0,sizeof(partialResource_s));
   
  memcpy(pr->key, fkey, sizeof(filekey_t));
  
  pr->status = CL_create();

  pr->size = end - start;

  pr->block_size = block_size;
  
  pr->current = 0;

  blockRange_s* blockRange = NULL;

  if( !(blockRange = malloc(sizeof(blockRange_s))) )
  {
    LOG_add(LOG_ERROR, RSRCMAN"malloc failed in %s at %s.",
                __func__,__LINE__);
    return NULL;               
  }

  memset(blockRange,0,sizeof(blockRange_s));

  blockRange->bstatus = BSTAT_NONE;
  blockRange->pid = 0;
  blockRange->begin = 0;
  blockRange->end = pr->size - 1;

  CL_push(pr->status, blockRange);

  char* filename = get_resource_filename_from_key(fkey);

  if(!filename) return NULL;

  // Open the part file.
  if( (pr->fd = open(filename,O_WRONLY)) == -1 )
  {
    LOG_add(LOG_ERROR, RSRCMAN"can't open %s: %s",
              filename,
              strerror(errno));
    return NULL;
  }

  free(filename);

  LOG_add(LOG_NOTICE,
            RSRCMAN"partial resource %32.32s created.",
            pr->key);

  return pr;
}

void RMC_destroy_partial_resource( partialResource_s* pr)
{
  if(!pr) return;

  // Clean & destroy
  CL_map(pr->status,free);
  CL_destroy(pr->status);

  // Open the part file.
  if( close(pr->fd) == -1 )
  {
    LOG_add(LOG_ERROR, RSRCMAN"can't close resource %32.32s: %s",
              pr->key,
              strerror(errno));

    return;
  }

  LOG_add(LOG_NOTICE,
            RSRCMAN"partial resource %32.32s destroyed.",
            pr->key);
 
  free(pr);

  return;
}

size_t RMC_write( partialResource_s* pr,
                    void* data,
                    size_t size )
{
  size_t w;

  w = RMC_write_offset( pr, data, size, pr->current);

  pr->current += w;

  return 0;
}

size_t RMC_write_offset( partialResource_s* pr,
                          void* data,
                          size_t size,
                          off_t offset )
{
  if( !data) return 0;

  size_t w=0;

  w = pwrite(pr->fd, data, size, offset);

  if( w == -1 )
  {
    LOG_add(LOG_ERROR,
            RSRCMAN"pwrite failed at %d in %d: %s\n",
            __LINE__,
            __FILE__,
            strerror(errno));
    return w;
  }

  _RM_set_range_state( pr->status,
                        w,
                        BSTAT_RMC_NONE_SENT,
                        0,
                        offset,
                        size + offset);

  _RM_stick_adjacent( pr->status );
  
  return w;
}

size_t RMC_read( partialResource_s* pr,
                  void* data,
                  size_t size,
                  off_t offset)
{
  if(!data) return 0;

  size_t w=0;

  w = pread(pr->fd, data, size, offset);

  return w;
}

range_s RMC_get_valid_range( partialResource_s* pr)
{
  CLNode_s* node;

  blockRange_s* nbr;

  for(node= CL_first(pr->status); node; node=node->next)
  {
    blockRange_s* br = node->data;
    
    // the byte range is not sent
    if( br->bstatus == BSTAT_RMC_NONE_SENT )
    {
      // If the byte range is longer than a single
      //block
      if( SIZE(br) > pr->block_size )
      {        
        size_t rem = SIZE(br)%(pr->block_size);
        
        size_t remd = (br->begin)%(pr->block_size);

        size_t db = 
          (pr->block_size)
           *ceil((double)(br->begin)/(double)(pr->block_size));

        if(remd)
        { // remd != 0
          
          if( !(nbr = malloc( sizeof(localResource_s))) )
          {
            LOG_add(LOG_ERROR,
                        RSRCMAN"malloc failed in %s at %s.",
                        __func__,__LINE__);
            return (range_s){-1,-1};
          }

          memset(nbr,0,sizeof(localResource_s));
       
          nbr->bstatus = BSTAT_RMC_NONE_SENT;
          nbr->begin = br->begin;
          nbr->end = db - 1;
          
          CL_push( pr->status, nbr);

          br->begin = nbr->end + 1;
        }

        if(!rem)
        { // rem == 0
          free(br);
          CL_remove(node);
        }
        else
        {

          if( !(nbr = malloc( sizeof(localResource_s))) )
          {
            LOG_add(LOG_ERROR,
                        RSRCMAN"malloc failed in %s at %s.",
                        __func__,__LINE__);
            return (range_s){-1,-1};
          }

          memset(nbr,0,sizeof(localResource_s));

          nbr->bstatus = BSTAT_RMC_NONE_SENT;
          nbr->begin = br->end - rem + 1;
          nbr->end = br->end;
          
          CL_push( pr->status, nbr );

          br->end = nbr->begin - 1;

          br->bstatus = BSTAT_RMC_SENT;
  
        }
        
        _RM_stick_adjacent( pr->status );

        return (range_s){br->begin, br->end};
      }

    }
  }
  
  return (range_s){-1,-1};
}

/***********************************************************/
/***********************************************************/
/***********************************************************/
/***********************************************************/

char fmatching_writing( int state, blockRange_s* br, pid_t pid)
{

  if( state == 0 )
    if( !((br->bstatus == BSTAT_POSTPONED)
            &&(br->pid==pid) ) )
      return 0;

  if( state == 1 )
    if( !(br->bstatus == BSTAT_NONE) )
      return 0;

  if( state == 2 )
    if( !(br->bstatus == BSTAT_POSTPONED) )
      return 0;
 
 return 1;
}

char fmatching_postponed( int state, blockRange_s* br, pid_t pid)
{
  if( state == 0 )
    if( !( br->bstatus == BSTAT_NONE ) )
      return 0;

  return 1;
}

